
const WebExcel = (function (w) {
  // to-do
  const WebExcel = function () {
    
  };

  WebExcel.util = (() => {
    const formatHeaderStr = (n) => {
      if (n < 26) {
        return String.fromCharCode(65 + n);
      } else {
        return formatHeaderStr(Math.floor(n / 26) - 1) + '' + formatHeaderStr(n % 26);
      }
    }

    return {
      formatHeaderStr: formatHeaderStr
    }
  })();

  const defaultOptions = {
    firstHeight: 24,
    firstWidth: 30,
    rowHeight: '20px',
    columnWidth: '80px',
    showGrid: true,
    columnLength: 10,
    rowLength: 12,
    data: null
  };

  const Grid = function (options) {
    this.cellsData = null;
    this.cells = null;
    this.currentCell = null;
    this.prevCell = null; // 之前选中的cell
    this.wrapper = null;
    this.resizeLocked = true;
    this.isResizeRow = false;
    this.isResizeColumn = false;
    this.data = options.data;
    this.resizeStartPosition = null;
    this.resizeEndPosition = null;
    this.activeColumnIndex = 0; // resize used
    this.activeRowIndex = 0; // resize used
    this.selectedColumnIndex = 0; // select used
    this.selectedRowIndex = 0; // select used

    this.rowHeader = null;
    this.columnHeader = null;
    this.gridBody = null;

    this.row = {
      cells: [],
      heights: Array(options.rowLength).fill(options.rowHeight)
    };
    this.column = {
      cells: [],
      widths: Array(options.columnLength).fill(options.columnWidth)
    };

    this.rowLength = options.rowLength;
    this.columnLength = options.columnLength;

    const createDomByTagName = (name) => {
      return document.createElement(name.toUpperCase());
    };
  
    const createWrapper = () => {
      const wrapper = createDomByTagName('DIV');
      wrapper.classList.add('main-wrapper');
      return wrapper;
    }

    function renderGridFirstBlock (container) {
      const firstBlock = createDomByTagName('div');
      firstBlock.classList.add('grid-first-block');
      firstBlock.innerHTML = '';
      container.appendChild(firstBlock);
      return firstBlock;
    }

    /**
     * 返回行头
     */
    const renderGridRowHeader = (container, index, count) => {
      const rowHeader = createDomByTagName('div');
      rowHeader.classList.add('grid-row-header');
      rowHeader.style.gridTemplateColumns = this.column.widths.join(' ');

      for (let i = 0; i < count; i++) {
        const rowHeaderCell = createDomByTagName('div');
        rowHeaderCell.classList.add('grid-row-header-cell');
        rowHeaderCell.classList.add('wbx-cell');
        const str = WebExcel.util.formatHeaderStr(i);
        rowHeaderCell.innerHTML = str;
        rowHeaderCell.index = i;

        // add border
        if (i === 0) {
          rowHeaderCell.classList.add('grid-row-header-cell-first');
        }

        // 添加行头 resize bar
        addColumnResizeBar(rowHeaderCell);

        rowHeader.appendChild(rowHeaderCell);
      }
      // this.rowHeader = rowHeader;

      rowHeader.onmousedown = onGridRowHeaderMouseDown;

      container.appendChild(rowHeader);

      return rowHeader;
    }

    // events
    const onGridRowHeaderMouseDown = (e) => {
      const target = e.target;
      if (target.classList.contains('grid-row-header-cell')) {

        // target.classList.add('column-active');
        
        // console.log(this.selectedColumnIndex);

        hideMenu();
        unselectRow();
        unselectColumn();
        unselectBodyCell();
        
        selectOneColumn(target.index);
      }
    };

    const selectOneColumn = (index) => {
      // highlight header cell
      highlightRowHeader(index);

      // highlight body cells
      this.column.cells[index].forEach(cell => {
        cell.classList.add('column-active');
      })

      this.selectedColumnIndex = index;
    };

    const highlightRowHeader = (index) => {
      this.rowHeader.children[index]
        .classList.add('column-active');
    }

    const highlightColumnHeader = (index) => {
      this.columnHeader.children[index]
        .classList.add('row-active');
    }

    const unselectColumn = () => {
      // unselect header cell
      this.rowHeader.children[this.selectedColumnIndex]
        .classList.remove('column-active');

      // unselect body cell
      if (this.column.cells[this.selectedColumnIndex]) {
        this.column.cells[this.selectedColumnIndex].forEach(cell => {
          cell.classList.remove('column-active');
        })
      }
    }

    /**
     * 返回列头
     */
    const renderGridColumnHeader = (container, index, count) => {
      const columnHeader = createDomByTagName('div');
      columnHeader.classList.add('grid-column-header');
      
      columnHeader.style.gridTemplateRows = this.row.heights.join(' ');

      for (let i = 0; i < count; i++) {
        const columnHeaderCell = createDomByTagName('div');
        columnHeaderCell.classList.add('grid-column-header-cell');
        columnHeaderCell.classList.add('wbx-cell');
      
        columnHeaderCell.innerHTML = i + 1;
        columnHeaderCell.index = i;

        // add border
        if (i === 0) {
          columnHeaderCell.classList.add('grid-column-header-cell-first');
        }

        // 添加列头 resize bar
        addRowResizeBar(columnHeaderCell);``

        columnHeader.appendChild(columnHeaderCell);
      }

      // add event
      columnHeader.onmousedown = onGridColumnHeaderMouseDown;
      // columnHeader.onmouseup = onGridColumnHeaderMouseUp;
      columnHeader.oncontextmenu = (e) => { return false };
      // columnHeader.onmouseup = (e) => { return false };

      container.appendChild(columnHeader);

      return columnHeader;
    };

    const onGridColumnHeaderMouseDown = (e) => {
      const target = e.target;
      if (target.classList.contains('grid-column-header-cell')) {
        
        unselectColumn();
        unselectBodyCell();
        unselectRow();
        hideMenu();
        
        selectOneRow(target.index);
      }
      
      // e.button: 0左键 1中键 2右键
      // see: https://developer.mozilla.org/zh-CN/docs/Web/Events/mousedown
      if (e.button === 2) {
        showMenu(e);
      }

      e.preventDefault();
      e.stopPropagation();
      e.cancelBubble = true
      e.returnValue = false;
      return false;
    }

    // 阻止鼠标右键菜单
    const onGridColumnHeaderMouseUp = (e) => {
      console.log('-------------------')
      e.preventDefault();
      e.stopPropagation();
      e.cancelBubble = true
      e.returnValue = false;
      return false;
    }

    const showMenu = (e) => {
      const gridX = this.wrapper.offsetLeft;
      const gridY = this.wrapper.offsetTop;

      const left = e.clientX - gridX + 2;
      const top = e.clientY - gridY + 2;

      console.log('x:', e.clientX - gridX, 'y:', e.clientY - gridY);
      this.menu.style.display = 'block';
      this.menu.style.top = top + 'px';
      this.menu.style.left = left + 'px';
    }

    const hideMenu = () => {
      this.menu.style.display = 'none';
    }

    const selectOneRow = (index) => {
      // select header cell
      highlightColumnHeader(index)

      // select body cell
      this.row.cells[index].forEach(cell => {
        cell.classList.add('row-active');
      })

      this.selectedRowIndex = index;
    }

    const unselectRow = () => {
      // 如果删除是最后一行 那就不用unselect
      if (this.columnHeader.children[this.selectedRowIndex]) {
        // unselect header cell
        this.columnHeader.children[this.selectedRowIndex]
        .classList.remove('row-active');
  
        // unselect body cell
        if (this.row.cells[this.selectedRowIndex]) {
          this.row.cells[this.selectedRowIndex].forEach(cell => {
            cell.classList.remove('row-active');
          })
        }
      }
    }

    const renderGridBody = (container, data) => {
      const gridBody = createDomByTagName('div');
      gridBody.classList.add('grid-body');

      gridBody.style.gridTemplateColumns = this.column.widths.join(' ');
      gridBody.style.gridTemplateRows = this.row.heights.join(' ');

      const cells = data.map((oneRow, rowIndex) => {
        return oneRow.map((oneRowColumn, columnIndex) => {
          // return rowIndex + ':' + columnIndex;
          return  createOneCell(data, rowIndex, columnIndex);
        })
      })

      console.log('cells data:\n', cells);

      this.cells = cells;
      
      let currentCell = null;
      
      // reset
      this.row.cells = [];
      this.column.cells = [];
  
      for (let i = 0; i < this.rowLength; i++ ) {
        // init row.cells
        if (typeof this.row.cells[i] === 'undefined') {
          this.row.cells[i] = cells[i];
        }
        for (let j = 0; j < this.columnLength; j++ ) {
          currentCell = cells[i][j];
          // init column.cells
          if (typeof this.column.cells[j] == 'undefined') {
            this.column.cells[j] = [];
          }
          this.column.cells[j].push(currentCell);
          gridBody.appendChild(currentCell);
        }
      }

      container.appendChild(gridBody);

      // this.gridBody = gridBody;

      // add event listeners
      gridBody.onmousedown = onGridBodyMouseDown;

      return gridBody;

    };

    // 单点一个单元格
    const onGridBodyMouseDown = (e) => {

      unselectColumn();
      unselectRow();
      hideMenu();

      const target = e.target;
      if (target.classList.contains('wbx-cell')) {
        unselectBodyCell();
        selectBodyCell(target);
      }
    };

    const selectBodyCell = (cell) => {
      cell.classList.add('active');
      this.currentCell = cell;
    }

    const unselectBodyCell = () => {
      if (this.currentCell) {
        this.currentCell.classList.remove('active');
      }
    }

    /**
     * 菜单
     */
    const renderGridMenu = (container) => {
      const menu = createDomByTagName('div');
      menu.classList.add('grid-menu');
      const htmlStr = `
        <ul>
          <li class="grid-menu-insert"><a class="grid-menu-insert">插入</a></li>
          <li class="grid-menu-delete"><a class="grid-menu-delete">删除</a></li>
        </ul>
      `
      menu.innerHTML = htmlStr;
      container.appendChild(menu);

      // add events
      menu.onclick = onMenuClick;

      return menu;
    }

    const onMenuClick = (e) => {
      const target = e.target;
      if (target.classList.contains('grid-menu-insert')) {
        console.log(this.selectedRowIndex);
        insertOneRow(this.selectedRowIndex);
      } else if (target.classList.contains('grid-menu-delete')) {
        deleteOneRow(this.selectedRowIndex);
      }
      hideMenu();
    }
  
    /**
     * 通过数据和配置 初始化表格
     * @param
     * @return wrapper dom节点
     */
    const renderGridDom = (data, options) => {
      const gridWrapper = createDomByTagName('div');
      gridWrapper.classList.add('grid-wrapper');

      this.wrapper = gridWrapper;

      this.firstBlock = renderGridFirstBlock(gridWrapper);
      
      this.rowHeader = renderGridRowHeader(gridWrapper, 0, this.columnLength);

      this.columnHeader = renderGridColumnHeader(gridWrapper, 0, this.rowLength);

      this.gridBody = renderGridBody(gridWrapper, data);

      this.menu = renderGridMenu(gridWrapper);

      return gridWrapper;

    };
  
    /**
     * 生成一个dom节点
     * @param {*} data 
     * @param {*} rowIndex 
     * @param {*} columnIndex 
     * @return dom
     */
    const createOneCell = (data, rowIndex, columnIndex) => {
      const cell = createDomByTagName('DIV');
      cell.classList.add('wbx-' + rowIndex + '-' + columnIndex);
      cell.classList.add('wbx-cell');

      cell.innerHTML = data[rowIndex][columnIndex];
      
      // add cell param
      cell.rowIndex = rowIndex;
      cell.columnIndex = columnIndex;

      // modify border collapse
      if (rowIndex === this.rowLength - 1 ) {
        cell.classList.add('wbx-cell-last-row');
      }
      
      return cell;
    };

    const addCellListener = (cell) => {
      cell.onclick = (event) => {
        event.target.style.backgroundColor = 'orange';
        console.log(event.target.innerHTML);
      }
    };

    const addColumnResizeBar = (cell) => {
      const bar = createDomByTagName('span');
      const barInner = createDomByTagName('span');
      
      bar.classList.add('column-resize-bar');
      bar.appendChild(barInner);

      bar.columnIndex = cell.index;
      barInner.columnIndex = cell.index;
      
      bar.onmousedown = onColumnResizeBarMouseDown.bind(this);
      
      cell.appendChild(bar);
    };

    const addRowResizeBar = (cell) => {
      const bar = createDomByTagName('span');
      const barInner = createDomByTagName('span');
      
      bar.appendChild(barInner);
      bar.classList.add('row-resize-bar');
      
      bar.rowIndex = cell.index;
      barInner.rowIndex = cell.index;
      
      bar.onmousedown = onRowResizeBarMouseDown.bind(this);
      
      cell.appendChild(bar);
    };

    function onRowResizeBarMouseDown (e) {
      console.log('onRowResizeBarMouseDown');
      this.resizeLocked = false;
      this.isResizeRow = true;

      this.activeRowIndex = e.target.rowIndex;
      
      let startHeight = parseInt(this.row.heights[this.activeRowIndex])
      if (isNaN(startHeight)) {
        startHeight = e.target.parent.height;
      }

      this.resizeStartPosition = {
        x: e.clientX,
        y: e.clientY,
        height: startHeight
      }

      return false;
      
    }


    function onColumnResizeBarMouseDown (e) {
      // 只有鼠标左键按下才行
      if (e.button === 0) {
        console.log('onColumnResizeBarMouseDown');
        this.resizeLocked = false;
        this.isResizeColumn = true;
  
        this.activeColumnIndex = e.target.columnIndex;
        
        this.resizeStartPosition = {
          x: e.clientX,
          y: e.clientY,
          width: parseInt(this.column.widths[this.activeColumnIndex])
        }
      }
      return false;
    };

    /**
     * 将json数据转换为二维数组数据
     * @param
     * @return {string[][]} 二维数组数据
     */
    const transformData = (data) => {
      // 有数据 行列以数据为准
      if (data) {
        const fields = data.fields;
  
        // 第一列是空
        fields.unshift('');
  
        let items = data.items;
        // 第一列是编号
        items = items.map((item, index) => {
          item.unshift(index + 1);
          return item;
        })
  
        if (fields.length > 0) {
          this.columnLength = fields.length;
          this.rowLength = items.length + 1;
          const cellsData = items;
          cellsData.unshift(fields);
          return cellsData;
        } else {
          return null;
        }
      } else {
        // 没有数据 生成空的行列
        let cellsData = [];
        for (let i = 0; i < this.rowLength; i++) {
          if (typeof cellsData[i] === 'undefined') {
            cellsData[i] = [];
          }
          for (let j = 0; j < this.columnLength; j++) {
            // cellsData[i].push('');
            cellsData[i].push(`${i}:${j}`);
          }
        }
        return cellsData;
      }
    };

    /*****************************************************
     * start 
     *****************************************************/

    // 构建数据
    this.cellsData = transformData(this.data);
    
    // 构建Dom
    const gridDom = renderGridDom(this.cellsData);

    // 添加事件
    function onGridWrapperMouseMove(e) {
      if (!this.resizeLocked) {
        if (this.isResizeColumn) {
          const startX = this.resizeStartPosition.x;
          const width = this.resizeStartPosition.width;
  
          const x = e.clientX;
          const xDiff = x - startX;
  
          let newWidth = width + xDiff;
          if (newWidth < 0) {
            newWidth = 0;
          }
          // console.log(xDiff);
          resizeColumnHeaderWidth(this.activeColumnIndex, newWidth);
        } else if (this.isResizeRow) {
          const startY = this.resizeStartPosition.y;
          const height = this.resizeStartPosition.height;
          
          const yDiff = e.clientY - startY;
          let newHeight = height + yDiff;
          if (newHeight < 0) {
            newHeight = 0;
          }

          resizeRowHeaderHeight(this.activeRowIndex, newHeight);

        }
      }
    }

    const resizeColumnHeaderWidth = (index, newWidth) => {
      console.log(newWidth + 'px');
      // render
      this.column.widths[index] = newWidth + 'px';
      this.rowHeader.style.gridTemplateColumns = this.column.widths.join(' ');
      // console.log(this.column.widths[index]);
    }

    const resizeRowHeaderHeight = (index, newHeight) => {
      console.log(newHeight + 'px');
      // render
      this.row.heights[index] = newHeight + 'px';
      this.columnHeader.style.gridTemplateRows = this.row.heights.join(' ');
    }

    function onGridWrapperMouseUp(e) {
      console.log('wrapper on mouse up');
      console.log('this.resizeLocked: ', this.resizeLocked);
      
      // render grid-body
      if (this.isResizeColumn) {
        this.gridBody.style.gridTemplateColumns = this.rowHeader.style.gridTemplateColumns;
      }

      if (this.isResizeRow) {
        this.gridBody.style.gridTemplateRows = this.columnHeader.style.gridTemplateRows;
      }

      this.resizeLocked = true;
      this.isResizeColumn = false;
      this.isResizeRow = false;
    }

    this.wrapper.onmousemove = onGridWrapperMouseMove.bind(this);

    this.wrapper.onmouseup = onGridWrapperMouseUp.bind(this);

    // 添加进页面
    root.appendChild(gridDom);

    const deleteOneRow = (rowIndex) => {
      console.log(this.row.cells);
      this.rowLength -= 1;
      
      this.cellsData.splice(rowIndex, 1);
      this.row.heights.splice(rowIndex, 1);

      // re-render
      this.rowHeader.remove();
      this.columnHeader.remove();
      this.gridBody.remove();

      this.rowHeader = renderGridRowHeader(this.wrapper, 0, this.columnLength);
      this.columnHeader = renderGridColumnHeader(this.wrapper, 0, this.rowLength);
      this.gridBody = renderGridBody(this.wrapper, this.cellsData);
    }

    const insertOneRow = (rowIndex) => {
      this.rowLength += 1;

      this.cellsData.splice(rowIndex, 0, Array(this.columnLength).fill(''));
      this.row.heights.splice(rowIndex, 0, defaultOptions.rowHeight)

      // re-render
      this.rowHeader.remove();
      this.columnHeader.remove();
      this.gridBody.remove();
      
      this.rowHeader = renderGridRowHeader(this.wrapper, 0, this.columnLength);
      this.columnHeader = renderGridColumnHeader(this.wrapper, 0, this.rowLength);
      this.gridBody = renderGridBody(this.wrapper, this.cellsData);
      
    }

    // exports
    return {
      deleteOneRow: deleteOneRow,
      insertOneRow: insertOneRow
    }

  }

  // Grid.prototype.deleteOneColumn = function deleteOneColumn(columnIndex) {}
  // Grid.prototype.insertOneRow = function insertOneRow(columnIndex) {}
  // Grid.prototype.insertOneColumn = function insertOneColumn(columnIndex) {}
  // Grid.prototype.resizeColumn = function resizeColumn(columnIndex) {}
  // Grid.prototype.resizeRow = function resizeRow(columnIndex) {}

  /**
   * 初始化载入
   */
  WebExcel.load = (root, options) => {

    // console.log('transformed data:\n', cellsData);
    const mergedOptions = Object.assign({}, defaultOptions, options);
    
    const grid = new Grid(mergedOptions);

    // root.appendChild(grid.wrapper);

    return grid;
  }
  
  WebExcel.init = () => {
    console.log('init test');
  };
  
  window.WebExcel = WebExcel;

  return WebExcel;
})(window);


module.exports = WebExcel;